﻿using Aliyun.OSS;
using Aliyun.OSS.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Aliyun.OSS.Util;
using Xwltz.Standard.Framework;

namespace Xwltz.Standard.Cloud
{
    public class BaseService
    {
        protected static readonly ClientConfiguration Conf = new ClientConfiguration();
        protected static readonly OssClient Client = new OssClient(FrameworkConfigs.EndPoint, FrameworkConfigs.AccessKeyId, FrameworkConfigs.AccessKeySecret, Conf);

        private static string _bucketName = "xwltz";
        protected static string BucketName
        {
            get => string.IsNullOrEmpty(_bucketName) ? null : _bucketName;
            set => _bucketName = value;
        }

        protected BaseService()
        {
            Conf.MaxErrorRetry = 3; // 请求发生错误时最大重试次数
            Conf.ConnectionTimeout = -1; //	设置连接超时时间，单位毫秒，默认不超时
            Conf.SetCustomEpochTicks(0); //设置自定义基准时间，即与本机时间差，单位秒
            Conf.IsCname = false; //Endpoint是否是Cname
            Conf.ProgressUpdateInterval = 8096; //进度条更新间隔，单位字节
            Conf.EnalbeMD5Check = false; //对上传下载的数据自动进行MD5校验
        }
    }

    public class OssService : BaseService
    {
        #region Bucket基础

        /// <summary>
        ///     查询存储空间是否存在
        /// </summary>
        /// <returns></returns>
        public static bool DoesBucketExist()
        {
            return Client.DoesBucketExist(BucketName.ToLower());
        }

        /// <summary>
        ///     创建存储空间
        /// </summary>
        /// <param name="access">设置访问权限</param>
        /// <returns></returns>
        public static bool CreateBucket(CannedAccessControlList access = CannedAccessControlList.Private)
        {
            if (DoesBucketExist()) return false;
            var bucket = Client.CreateBucket(BucketName.ToLower());
            SetBucketAcl(access);
            return bucket != null;
        }

        /// <summary>
        ///     设置存储空间的访问权限
        /// </summary>
        /// <param name="access">权限</param>
        public static void SetBucketAcl(CannedAccessControlList access = CannedAccessControlList.Private)
        {
            Client.SetBucketAcl(BucketName, access);
        }

        /// <summary>
        ///     获取存储空间的访问权限
        /// </summary>
        /// <returns></returns>
        public static AccessControlList GetBucketAcl()
        {
            return Client.GetBucketAcl(BucketName);
        }

        /// <summary>
        ///     删除存储空间
        /// </summary>
        public static void DeleteBucket()
        {
            Client.DeleteBucket(BucketName);
        }

        /// <summary>
        ///     获取所有存储空间
        /// </summary>
        /// <returns></returns>
        public static List<Bucket> ListBuckets()
        {
            var buckets = Client.ListBuckets().ToList();
            return buckets.ToList();
        }

        #endregion

        #region 日志

        /// <summary>
        ///     开启日志功能
        /// </summary>
        public static void SetBucketLogging()
        {
            var request = new SetBucketLoggingRequest(BucketName, BucketName, "logging-");
            Client.SetBucketLogging(request);
        }

        /// <summary>
        ///     查看日志设置
        /// </summary>
        /// <returns></returns>
        public static BucketLoggingResult GetBucketLogging()
        {
            return Client.GetBucketLogging(BucketName);
        }

        /// <summary>
        ///     关闭日志功能
        /// </summary>
        public static void DeleteBucketLogging()
        {
            Client.DeleteBucketLogging(BucketName);
        }

        #endregion

        #region 跨域规则

        /// <summary>
        ///     设定CORS规则
        ///     var r1 = new CORSRule();--实例跨域规则
        ///     r1.AddAllowedOrigin("http://www.a.com");--指定允许跨域请求的来源
        ///     r1.AddAllowedMethod("POST");--指定允许的跨域请求方法(GET/PUT/DELETE/POST/HEAD)
        ///     r1.AddAllowedHeader("*");--控制在OPTIONS预取指令中Access-Control-Request-Headers头中指定的header是否允许。
        ///     r1.AddExposeHeader("x-oss-test");--指定允许用户从应用程序中访问的响应头
        /// </summary>
        /// <param name="rules"></param>
        public static void SetBucketCors(List<CORSRule> rules)
        {
            var request = new SetBucketCorsRequest(BucketName);
            foreach (var rule in rules)
            {
                request.AddCORSRule(rule);
            }
            Client.SetBucketCors(request);
        }

        /// <summary>
        ///     获取CORS规则
        /// </summary>
        /// <returns></returns>
        public static List<CORSRule> GetBucketCors()
        {

            var result = Client.GetBucketCors(BucketName);
            return result.ToList();
        }

        /// <summary>
        ///     删除CORS规则
        /// </summary>
        public static void DeleteBucketCors()
        {
            Client.DeleteBucketCors(BucketName);
        }

        #endregion

        #region 静态页面托管

        /// <summary>
        ///     设置静态页面托管
        /// </summary>
        /// <param name="index"></param>
        /// <param name="error"></param>
        public static void SetBucketWebsite(string index, string error)
        {
            var request = new SetBucketWebsiteRequest(BucketName, index, error);
            Client.SetBucketWebsite(request);
        }

        /// <summary>
        ///     获取静态托管页面
        /// </summary>
        public static BucketWebsiteResult GetBucketWebsite()
        {
            return Client.GetBucketWebsite(BucketName);
        }

        /// <summary>
        ///     删除静态页面托管
        /// </summary>
        public static void DeleteBucketWebsite()
        {
            Client.DeleteBucketWebsite(BucketName);
        }

        #endregion

        #region 防盗链

        /// <summary>
        ///     设置 防盗链 Referer白名单
        ///     Referer参数支持通配符“*”和“？”，更多详细的规则配置可以参考开发人员指南
        ///     https://help.aliyun.com/document_detail/31869.html?spm=5176.doc32096.2.2.IywF1I
        /// </summary>
        /// <param name="refererList"></param>
        public static void SetBucketReferer(List<string> refererList)
        {
            var srq = new SetBucketRefererRequest(BucketName, refererList);
            Client.SetBucketReferer(srq);
        }

        /// <summary>
        ///     获取 防盗链 Referer白名单
        /// </summary>
        /// <returns></returns>
        public static RefererConfiguration GetBucketReferer()
        {
            var rc = Client.GetBucketReferer(BucketName);
            return rc;
        }

        /// <summary>
        ///     清空 防盗链 Referer白名单
        /// </summary>
        /// <returns></returns>
        public static void DeleteBucketReferer()
        {
            var request = new SetBucketRefererRequest(BucketName);
            Client.SetBucketReferer(request);
        }
        #endregion

        #region 设置生命周期

        /// <summary>
        ///     设置生命周期
        ///     var lcr1 = new LifecycleRule();--实例生命周期规则
        ///     lcr1.ID = "delete obsoleted files";--用来唯一表示本条规则
        ///     lcr1.Prefix = "obsoleted/";--指定对存储空间下的符合特定前缀的文件使用规则,不能重叠
        ///     lcr1.Status = RuleStatus.Enabled;--指定本条规则的状态,只有Enabled和Disabled,分别表示启用规则和禁用规则
        ///     lcr1.Expiration = 3;--Expiration节点里面的Days表示大于文件最后修改时间指定的天数就删除文件，Date则表示到指定的绝对时间之后就删除文件(绝对时间服从ISO8601的格式)。
        /// </summary>
        /// <param name="lcrs"></param>
        public static void SetBucketLifecycle(List<LifecycleRule> lcrs)
        {
            var setBucketLifecycleRequest = new SetBucketLifecycleRequest(BucketName);
            foreach (var lcr in lcrs)
            {
                setBucketLifecycleRequest.AddLifecycleRule(lcr);
            }
            Client.SetBucketLifecycle(setBucketLifecycleRequest);
        }

        /// <summary>
        ///     获取生命周期
        /// </summary>
        /// <returns></returns>
        public static List<LifecycleRule> GetBucketLifecycle()
        {
            var rules = Client.GetBucketLifecycle(BucketName);
            return rules.ToList();
        }

        /// <summary>
        ///     清空生命周期
        /// </summary>
        /// <returns></returns>
        public static void DeleteBucketLifecycle()
        {
            var lc = new SetBucketLifecycleRequest(BucketName);
            Client.SetBucketLifecycle(lc);
        }

        #endregion

        #region PUT操作

        /// <summary>
        /// 创建模拟文件夹
        /// </summary>
        /// <param name="folder">文件夹名称 必须用/为结尾</param>
        /// <returns></returns>
        public static PutObjectResult PutObjectFolder(string folder)
        {
            try
            {
                using (var stream = new MemoryStream())
                {
                    return Client.PutObject(BucketName, folder, stream);
                }
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
            return null;
        }

        /// <summary>
        /// 上传指定文件并且带MD5校验
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <param name="file">本地文件路径 PS:必须为本地文件</param>
        /// <returns></returns>
        public static PutObjectResult PutObject(string file, string filename)
        {
            string md5;
            using (var fs = File.Open(file, FileMode.Open))
            {
                md5 = OssUtils.ComputeContentMd5(fs, fs.Length);
            }

            var meta = new ObjectMetadata { ContentMd5 = md5 };

            if (string.IsNullOrEmpty(filename))
            {
                var suffx = file.Substring(file.IndexOf(".", StringComparison.Ordinal));
                filename = "default/" + DateTime.Now.ToString("yyyyMMdd") + "/" + Guid.NewGuid().ToString().ToUpper() + suffx;
            }
            //设置文件权限
            Client.SetObjectAcl(BucketName, filename, CannedAccessControlList.Default);

            return Client.PutObject(BucketName, filename, file, meta);
        }

        #endregion
    }
}
